"""
前后端接口层
"""
import os
import sys
import threading
import time
import queue
from typing import Dict, Any, Optional, Callable

# 修复后端路径问题
def _add_backend_path():
    """添加后端路径到sys.path"""
    current_dir = os.path.dirname(os.path.abspath(__file__))

    # 可能的后端路径
    possible_paths = [
        # 从 src/frontend 到 src/backend
        os.path.join(os.path.dirname(current_dir), 'backend'),
        # 从项目根目录的backend
        os.path.join(os.path.dirname(os.path.dirname(current_dir)), 'backend'),
        # 相对路径
        os.path.join(current_dir, '..', 'backend'),
    ]

    for path in possible_paths:
        if os.path.exists(path) and path not in sys.path:
            sys.path.insert(0, path)
            print(f"添加后端路径: {path}")

# 添加后端路径
_add_backend_path()

# 尝试导入后端适配器
try:
    from backend_adapter import BackendAdapter
    HAS_BACKEND = True
    print("成功导入后端适配器")
except ImportError as e:
    print(f"警告：无法导入后端适配器: {e}")
    print("将使用模拟后端")
    HAS_BACKEND = False
    BackendAdapter = None

class MockBackendAdapter:
    """模拟后端适配器，用于测试前端UI"""

    def __init__(self):
        self.episode = 0
        self.round = 0
        self.score = 0
        self.player_hp = 100
        self.player_pos = {"x": 8, "y": 8}
        self.game_over = False
        self.is_training = False
        self.ai_control = True

        # 简单地图
        self.map_data = [[0 for _ in range(17)] for _ in range(17)]
        for i in range(17):
            self.map_data[0][i] = 1
            self.map_data[16][i] = 1
            self.map_data[i][0] = 1
            self.map_data[i][16] = 1

        self.enemies = [{"x": 5, "y": 5, "hp": 50, "type": "skeleton"}]
        self.treasures = [{"x": 10, "y": 10, "value": 100, "collected": False}]
        self.traps = [{"x": 6, "y": 6, "damage": 10, "triggered": False}]

        print("模拟后端适配器初始化完成")

    def get_game_state(self) -> Dict[str, Any]:
        """获取游戏状态"""
        return {
            "map": self.map_data,
            "player": {
                "x": self.player_pos["x"],
                "y": self.player_pos["y"],
                "hp": self.player_hp,
                "max_hp": 100,
                "score": self.score
            },
            "enemies": self.enemies,
            "traps": self.traps,
            "treasures": self.treasures,
            "round": self.round,
            "score": self.score,
            "episode": self.episode,
            "game_over": self.game_over
        }

    def reset_game(self) -> Dict[str, Any]:
        """重置游戏"""
        self.episode += 1
        self.round = 0
        self.score = 0
        self.player_hp = 100
        self.player_pos = {"x": 8, "y": 8}
        self.game_over = False
        return self.get_game_state()

    def execute_action(self, action: int) -> Dict[str, Any]:
        """执行动作"""
        directions = [(1, 0), (0, 1), (-1, 0), (0, -1)]
        if 0 <= action < len(directions):
            dx, dy = directions[action]
            new_x = self.player_pos["x"] + dx
            new_y = self.player_pos["y"] + dy

            if 1 <= new_x <= 15 and 1 <= new_y <= 15:
                if self.map_data[new_y][new_x] == 0:
                    self.player_pos["x"] = new_x
                    self.player_pos["y"] = new_y
                    self.round += 1

        return {
            "state": self.get_game_state(),
            "reward": 0.1,
            "done": self.round > 100
        }

    def set_ai_control(self, enabled: bool):
        """设置AI控制"""
        self.ai_control = enabled

    def start_training(self, params: Dict[str, Any]):
        """开始训练"""
        self.is_training = True
        print(f"开始训练，参数: {params}")

    def stop_training(self):
        """停止训练"""
        self.is_training = False
        print("停止训练")

    def save_model(self, name: str) -> str:
        """保存模型"""
        path = f"checkpoints/{name}.pth"
        print(f"模拟保存模型到: {path}")
        return path

    def load_model(self, path: str):
        """加载模型"""
        print(f"模拟加载模型: {path}")

    def get_training_stats(self) -> Dict[str, Any]:
        """获取训练统计"""
        return {
            "episode": self.episode,
            "round": self.round,
            "score": self.score,
            "health": self.player_hp,
            "epsilon": 0.1,
            "avg_reward": 0.5,
            "loss": 0.01
        }

class BackendInterface:
    """前后端接口层 - 管理前后端通信"""

    def __init__(self):
        # 后端适配器
        self.backend = None
        self.connected = False

        # 状态缓存
        self.cached_state = None
        self.cached_stats = {}

        # 事件队列
        self.state_queue = queue.Queue(maxsize=100)
        self.command_queue = queue.Queue()

        # 监听器
        self.state_listeners = []
        self.stats_listeners = []
        self.message_listeners = []

        # 控制线程
        self.update_thread = None
        self.command_thread = None
        self.running = False

        # 初始化后端连接
        self._initialize_backend()

    def _initialize_backend(self):
        """初始化后端连接"""
        try:
            if HAS_BACKEND and BackendAdapter:
                self.backend = BackendAdapter()
                self.connected = True
                self._emit_message("真实后端连接成功")
            else:
                # 使用模拟后端
                self.backend = MockBackendAdapter()
                self.connected = True
                self._emit_message("使用模拟后端（用于UI测试）")

            # 启动更新线程
            self.start_threads()

            # 获取初始状态
            initial_state = self.backend.get_game_state()
            if initial_state:
                self.cached_state = initial_state
                self._emit_state_update(initial_state)

        except Exception as e:
            self.connected = False
            self._emit_message(f"后端连接失败: {e}")
            print(f"后端初始化错误: {e}")

    def start_threads(self):
        """启动后台线程"""
        self.running = True

        # 状态更新线程
        self.update_thread = threading.Thread(target=self._update_loop, daemon=True)
        self.update_thread.start()

        # 命令处理线程
        self.command_thread = threading.Thread(target=self._command_loop, daemon=True)
        self.command_thread.start()

    def stop_threads(self):
        """停止后台线程"""
        self.running = False

        if self.update_thread:
            self.update_thread.join(timeout=2)
        if self.command_thread:
            self.command_thread.join(timeout=2)

    def _update_loop(self):
        """状态更新循环"""
        while self.running:
            try:
                if self.connected and self.backend:
                    # 获取最新状态
                    state = self.backend.get_game_state()
                    if state and state != self.cached_state:
                        self.cached_state = state
                        self._emit_state_update(state)

                    # 获取训练统计
                    stats = self.backend.get_training_stats()
                    if stats and stats != self.cached_stats:
                        self.cached_stats = stats
                        self._emit_stats_update(stats)

                time.sleep(0.1)  # 10FPS更新频率

            except Exception as e:
                print(f"状态更新错误: {e}")
                time.sleep(1.0)

    def _command_loop(self):
        """命令处理循环"""
        while self.running:
            try:
                # 处理命令队列
                command = self.command_queue.get(timeout=1.0)
                self._execute_command(command)

            except queue.Empty:
                continue
            except Exception as e:
                print(f"命令处理错误: {e}")

    def _execute_command(self, command: Dict[str, Any]):
        """执行命令"""
        if not self.connected or not self.backend:
            self._emit_message("后端未连接，无法执行命令")
            return

        try:
            cmd_type = command.get("type")

            if cmd_type == "reset_game":
                state = self.backend.reset_game()
                self.cached_state = state
                self._emit_state_update(state)
                self._emit_message("游戏已重置")

            elif cmd_type == "execute_action":
                action = command.get("action", 0)
                result = self.backend.execute_action(action)

                new_state = result.get("state")
                if new_state:
                    self.cached_state = new_state
                    self._emit_state_update(new_state)

                if result.get("done"):
                    self._emit_message("游戏结束")

            elif cmd_type == "set_ai_control":
                enabled = command.get("enabled", True)
                self.backend.set_ai_control(enabled)
                mode = "AI控制" if enabled else "手动控制"
                self._emit_message(f"切换到{mode}模式")

            elif cmd_type == "start_training":
                params = command.get("params", {})
                self.backend.start_training(params)
                self._emit_message("训练已开始")

            elif cmd_type == "stop_training":
                self.backend.stop_training()
                self._emit_message("训练已停止")

            elif cmd_type == "save_model":
                name = command.get("name", "model")
                path = self.backend.save_model(name)
                self._emit_message(f"模型已保存: {path}")

            elif cmd_type == "load_model":
                path = command.get("path", "")
                self.backend.load_model(path)
                self._emit_message(f"模型已加载: {path}")

            else:
                self._emit_message(f"未知命令: {cmd_type}")

        except Exception as e:
            self._emit_message(f"命令执行失败: {e}")
            print(f"命令执行错误: {e}")

    # =========================
    # 公共接口方法
    # =========================

    def get_game_state(self) -> Optional[Dict[str, Any]]:
        """获取当前游戏状态"""
        if self.connected and self.backend:
            try:
                return self.backend.get_game_state()
            except Exception as e:
                print(f"获取游戏状态失败: {e}")

        return self.cached_state

    def reset_game(self):
        """重置游戏（异步）"""
        self._queue_command({"type": "reset_game"})

    def execute_action(self, action: int):
        """执行动作（异步）"""
        self._queue_command({"type": "execute_action", "action": action})

    def set_ai_control(self, enabled: bool):
        """设置AI控制（异步）"""
        self._queue_command({"type": "set_ai_control", "enabled": enabled})

    def start_training(self, params: Dict[str, Any]):
        """开始训练（异步）"""
        self._queue_command({"type": "start_training", "params": params})

    def stop_training(self):
        """停止训练（异步）"""
        self._queue_command({"type": "stop_training"})

    def save_model(self, name: str):
        """保存模型（异步）"""
        self._queue_command({"type": "save_model", "name": name})

    def load_model(self, path: str):
        """加载模型（异步）"""
        self._queue_command({"type": "load_model", "path": path})

    def get_training_stats(self) -> Dict[str, Any]:
        """获取训练统计"""
        if self.connected and self.backend:
            try:
                return self.backend.get_training_stats()
            except Exception as e:
                print(f"获取训练统计失败: {e}")

        return self.cached_stats

    def is_connected(self) -> bool:
        """检查后端连接状态"""
        return self.connected

    # =========================
    # 监听器管理
    # =========================

    def add_state_listener(self, listener: Callable[[Dict[str, Any]], None]):
        """添加状态监听器"""
        if listener not in self.state_listeners:
            self.state_listeners.append(listener)

    def remove_state_listener(self, listener: Callable[[Dict[str, Any]], None]):
        """移除状态监听器"""
        if listener in self.state_listeners:
            self.state_listeners.remove(listener)

    def add_stats_listener(self, listener: Callable[[Dict[str, Any]], None]):
        """添加统计监听器"""
        if listener not in self.stats_listeners:
            self.stats_listeners.append(listener)

    def remove_stats_listener(self, listener: Callable[[Dict[str, Any]], None]):
        """移除统计监听器"""
        if listener in self.stats_listeners:
            self.stats_listeners.remove(listener)

    def add_message_listener(self, listener: Callable[[str], None]):
        """添加消息监听器"""
        if listener not in self.message_listeners:
            self.message_listeners.append(listener)

    def remove_message_listener(self, listener: Callable[[str], None]):
        """移除消息监听器"""
        if listener in self.message_listeners:
            self.message_listeners.remove(listener)

    # =========================
    # 内部方法
    # =========================

    def _queue_command(self, command: Dict[str, Any]):
        """将命令添加到队列"""
        try:
            self.command_queue.put_nowait(command)
        except queue.Full:
            self._emit_message("命令队列已满")

    def _emit_state_update(self, state: Dict[str, Any]):
        """发送状态更新事件"""
        for listener in self.state_listeners[:]:  # 复制列表避免并发修改
            try:
                listener(state)
            except Exception as e:
                print(f"状态监听器错误: {e}")

    def _emit_stats_update(self, stats: Dict[str, Any]):
        """发送统计更新事件"""
        for listener in self.stats_listeners[:]:
            try:
                listener(stats)
            except Exception as e:
                print(f"统计监听器错误: {e}")

    def _emit_message(self, message: str):
        """发送消息事件"""
        for listener in self.message_listeners[:]:
            try:
                listener(message)
            except Exception as e:
                print(f"消息监听器错误: {e}")

    # =========================
    # 生命周期管理
    # =========================

    def cleanup(self):
        """清理资源"""
        self.stop_threads()

        if self.backend:
            try:
                # 保存自动备份
                self.backend.save_model("autosave")
            except:
                pass

        self.state_listeners.clear()
        self.stats_listeners.clear()
        self.message_listeners.clear()

    def __del__(self):
        """析构函数"""
        self.cleanup()

# 全局接口实例
_backend_interface = None

def get_backend_interface() -> BackendInterface:
    """获取全局后端接口实例"""
    global _backend_interface
    if _backend_interface is None:
        _backend_interface = BackendInterface()
    return _backend_interface

def cleanup_backend_interface():
    """清理全局后端接口"""
    global _backend_interface
    if _backend_interface:
        _backend_interface.cleanup()
        _backend_interface = None